fix(memory): resolve Vitest false positive for expected rejection#3893
fix(memory): resolve Vitest false positive for expected rejection#3893JosephDoUrden wants to merge 1 commit intomodelcontextprotocol:mainfrom
Conversation
Wrap the addObservations call in an async closure before asserting with .rejects.toThrow(). This prevents Vitest's global unhandled rejection handler from capturing the expected error before the assertion can intercept it, eliminating the false-positive "Unhandled Errors" warning that was failing CI. Fixes modelcontextprotocol#3073
olaservo
left a comment
There was a problem hiding this comment.
Correct fix for the well-known Vitest/Jest async rejection race. Wrapping in an async closure ensures the rejection is scoped to the expect chain. Clean and minimal.
This review was assisted by Claude Code.
|
@claude review |
|
Claude finished @cliffhall's task in 1m 13s —— View job Code Review
Verdict: LGTM — correct, minimal fix. What changed- await expect(
- manager.addObservations([
+ await expect(async () => {
+ await manager.addObservations([
{ entityName: 'NonExistent', contents: ['some observation'] },
- ])
- ).rejects.toThrow('Entity with name NonExistent not found');
+ ]);
+ }).rejects.toThrow('Entity with name NonExistent not found');
Root cause analysisLooking at the implementation in async addObservations(...): Promise<...> {
const graph = await this.loadGraph();
const results = observations.map(o => {
const entity = graph.entities.find(e => e.name === o.entityName);
if (!entity) {
throw new Error(`Entity with name ${o.entityName} not found`); // sync throw
}
...
});
...
}A synchronous throw inside an Wrapping in Review notes
This is a clean, well-understood fix for a known Vitest/Jest async-rejection timing issue. Already approved by @olaservo. Ready to merge. |
Summary
addObservationscall in an async closure before asserting with.rejects.toThrow(), so Vitest's global unhandled rejection handler does not capture the expected error before the assertion intercepts itFixes #3073
Root cause
addObservationsis an async function that throws synchronously inside a.map()callback. When passed directly toexpect().rejects.toThrow(), the resulting Promise rejection is seen by Vitest's global rejection handler before the.rejectswrapper can intercept it. Wrapping inasync () => { await ... }ensures the rejection is properly scoped.Changes
src/memory/__tests__/knowledge-graph.test.ts: Wrap the assertion in an async closureTest plan
npx vitest run)AI Disclosure
AI assistance (Claude) was used for issue research. The implementation was written and reviewed by the author.